
#include <math.h>
#include <stdio.h>

#include <util/mem.h>
#include <util/common_macros.h>
#include <util/math_macros.h>
#include <util/msg.h>

#include "rectangle.h"
#include "geometry.h"
#include "predicates.h"

#include "triangle.h"
#include "surface.h"

#include "../image/image.h"

//static long int count = 0;
//static void __rectangle_destroy(ImpObject * object) {
	//ImpRectangle * p;
	//p = IMP_RECTANGLE(object);

	/* do nothing */
//}
/*
static void __rectangle_class_init(ImpObjectClass * klass) {
	klass->object_clone = NULL;
	klass->object_destroy = __rectangle_destroy;
	klass->object_attributes = NULL;
}
static void __rectangle_init(ImpObject * object) {
	ImpRectangle * r;
	r = IMP_RECTANGLE(object);

	r->e1 = NULL;
	r->e2 = NULL;
	r->e3 = NULL;
	r->e4 = NULL;

}

// ===========================================================================
ImpRectangleClass * imp_rectangle_get_class(void) {
	static ImpRectangleClass * klass = NULL;

	if (klass == NULL) {
		ImpObjectClassInfo rectangle_info = {
											"ImpRectangle",
											sizeof (ImpRectangle),
											sizeof (ImpRectangleClass),
											(ImpObjectClassInitFunc) __rectangle_class_init,
											(ImpObjectInitFunc) __rectangle_init,
											(ImpArgSetFunc) NULL,
											(ImpArgGetFunc) NULL
		};

		ImpObjectClass * parent_class = imp_object_get_class();
		ImpObjectClass * rectangle_class = imp_object_class_new(parent_class, &rectangle_info);
		klass = IMP_RECTANGLE_CLASS(rectangle_class);
	}
	return klass;
}
ImpRectangle * imp_rectangle_new(ImpEdge * e1, ImpEdge * e2, ImpEdge * e3, ImpEdge * e4) {
	ImpRectangle * r;

	r = IMP_RECTANGLE(imp_object_new(IMP_OBJECT_CLASS(imp_rectangle_get_class())));

	imp_rectangle_set(r, e1, e2, e3, e4);
	r->id = count;
	count++;

	return r;
}
void imp_rectangle_set(ImpRectangle * r, ImpEdge * e1, ImpEdge * e2, ImpEdge * e3, ImpEdge * e4) {
	r->e1 = e1;
	r->e2 = e2;
	r->e3 = e3;
	r->e4 = e4;

	list_append(e1->faces, r);
	list_append(e2->faces, r);
	list_append(e3->faces, r);
	list_append(e4->faces, r);

}

// ===========================================================================
ImpSurface * imp_rectangle(ImpSurface * surf, ImpImage * img) {

	ListIterator * it;
	ImpTriangle * T;
	ImpTriangle * t1, * t2, * t3;

#define VISITED 1


	_exit_if_fail(surf);
	_exit_if_fail(img);

	it = surf->faces->first;
	while (it) {

		T = IMP_TRIANGLE(it->data);
		it = it->next;


		if (T->parent.flags == VISITED) continue;

		t1 = imp_triangle_get_opposite_triangle(T, T->e[0]);
		t2 = imp_triangle_get_opposite_triangle(T, T->e[1]);
		t3 = imp_triangle_get_opposite_triangle(T, T->e[2]);

	}
	return NULL;
}
ImpRectangle * __get_quad(ImpTriangle * T1, ImpTriangle * T2, ImpImage * img) {

	int bary1, bary2;
	ImpRectangle * rect = NULL;

	ImpVertex *v1, *v2, *v3, *v4;
	ImpEdge *es, *e1, *e2, *e3, *e4, *e5;

	ImpPoint p;

	if (!T2) return NULL;

	p = imp_triangle_barycenter(T1);
	bary1 = img->data[ imp_image_idx(img, p.x, p.y) ];

	p = imp_triangle_barycenter(T2);
	bary2 = img->data[ imp_image_idx(img, p.x, p.y) ];

	if (ABS(bary1 - bary2) <= 20) {
		imp_triangle_extract(T1, es, &v1, &v2, &v3, &e1, &e2, &e3);
		imp_triangle_extract(T2, es, &v1, &v2, &v4, &e1, &e4, &e5);
		rect = imp_rectangle_new(e2, e3, e4, e5);
	}
	return rect;
}
boolean __is_rect(ImpTriangle * T1, ImpTriangle * T2, ImpImage * img) {

	int bary1, bary2;

	ImpPoint p;

	_return_val_if_fail(T1 && T2, FALSE);

	p = imp_triangle_barycenter(T1);
	bary1 = img->data[ imp_image_idx(img, p.x, p.y) ]; //img->methods.get_pixel(img, (int) p.x, (int) p.y);

	p = imp_triangle_barycenter(T2);
	bary2 = img->data[ imp_image_idx(img, p.x, p.y) ]; //img->methods.get_pixel(img, (int) p.x, (int) p.y);

	if (ABS(bary1 - bary2) <= 0) return TRUE;

	return FALSE;
}
ImpSurface * __imp_rectangle_surface(ImpSurface * s, ImpImage * img) {

	ImpSurface * quads;

	ListIterator * it;
	ImpTriangle * T1, * T2;
	ImpRectangle * rect;

	ImpEdge *es;

	quads = imp_surface_new();

	it = s->faces->first;

	while (it) {

		T1 = IMP_TRIANGLE(it->data);
		it = it->next;

		rect = NULL;

		if (T1) {
			printf("     Triangle T1 = ");
			imp_triangle_print(T1);
			printf("\n");
		}

		int i;
		for (i = 0; i < 3; i++) {

			es = T1->e[i];
			T2 = imp_triangle_get_opposite_triangle(T1, es);

			if (T2) {
				printf("     Triangle T2 = ");
				imp_triangle_print(T2);
				printf("\n");
			}

			rect = __get_quad(T1, T2, img);

			if (rect) {
				//imp_surface_remove_edge(s, es);

				imp_surface_add_edge(quads, rect->e1);
				imp_surface_add_edge(quads, rect->e2);
				imp_surface_add_edge(quads, rect->e3);
				imp_surface_add_edge(quads, rect->e4);

				imp_surface_add_rectangle(quads, rect);
				continue;
			}

		}
	}
	return quads;
}
void imp_rectangle_surface(ImpSurface * quads, ImpSurface * s, ImpTriangle * T, ImpImage * img) {

	ImpTriangle * T1, * T2, * T3;
	ImpPoint p;
	ImpRectangle * rect;
	ImpEdge * es;
	ImpVertex *v1, *v2, *v3, *v4;
	ImpEdge *e1, *e2, *e3, *e4, *e5;

	int bary, bary2;


	T1 = imp_triangle_get_opposite_triangle(T, T->e[0]);
	T2 = imp_triangle_get_opposite_triangle(T, T->e[1]);
	T3 = imp_triangle_get_opposite_triangle(T, T->e[2]);

	if (T) {
		printf(" === Triangle T = ");
		imp_triangle_print(T);
		printf("\n");
	}
	if (T1) {
		printf("     Triangle T1 = ");
		imp_triangle_print(T1);
		printf("\n");
	}
	if (T2) {
		printf("     Triangle T2 = ");
		imp_triangle_print(T2);
		printf("\n");
	}
	if (T3) {
		printf("     Triangle T3 = ");
		imp_triangle_print(T3);
		printf("\n");
	}

	p = imp_triangle_barycenter(T);
	imp_triangle_extract(T, es, &v1, &v2, &v3, &e1, &e2, &e3);

	bary = img->data[ imp_image_idx(img, p.x, p.y) ]; //img->methods.get_pixel(img, (int) p.x, (int) p.y);

	// = T1 ==================================================================
	es = T->e[0];
	p = imp_triangle_barycenter(T1);
	bary2 = img->data[ imp_image_idx(img, p.x, p.y) ]; //img->methods.get_pixel(img, (int) p.x, (int) p.y);
	if (ABS(bary - bary2) <= 10) {

		imp_rectangle_surface(quads, s, T1, img);

		imp_triangle_extract(T1, es, &v1, &v2, &v4, &e1, &e4, &e5);
		rect = imp_rectangle_new(e2, e3, e4, e5);
		imp_surface_add_rectangle(quads, rect);

		imp_surface_remove_edge(s, es);
		imp_object_delete(es);
	} else {
		return;
	}

	// = T2 ==================================================================
	es = T->e[1];
	p = imp_triangle_barycenter(T2);
	bary2 = img->data[ imp_image_idx(img, p.x, p.y) ]; //img->methods.get_pixel(img, (int) p.x, (int) p.y);
	if (ABS(bary - bary2) <= 10) {

		imp_rectangle_surface(quads, s, T2, img);

		imp_triangle_extract(T2, es, &v1, &v2, &v4, &e1, &e4, &e5);
		rect = imp_rectangle_new(e2, e3, e4, e5);
		imp_surface_add_rectangle(quads, rect);

		imp_surface_remove_edge(s, es);
		imp_object_delete(es);

	} else {
		return;
		imp_rectangle_surface(quads, s, T2, img);
	}

	// = T3 ==================================================================
	es = T->e[2];
	p = imp_triangle_barycenter(T3);
	bary2 = img->data[ imp_image_idx(img, p.x, p.y) ]; //img->methods.get_pixel(img, (int) p.x, (int) p.y);
	if (ABS(bary - bary2) <= 10) {

		imp_rectangle_surface(quads, s, T3, img);

		imp_triangle_extract(T3, es, &v1, &v2, &v4, &e1, &e4, &e5);
		rect = imp_rectangle_new(e2, e3, e4, e5);
		imp_surface_add_rectangle(quads, rect);

		imp_surface_remove_edge(s, es);
		imp_object_delete(es);

	} else {
		return;
		imp_rectangle_surface(quads, s, T3, img);
	}

}
ImpSurface * _rec_test(ImpSurface * surf, ImpImage * img) {

	ImpSurface * quads;
	ImpTriangle *T, *T1, *T2, *T3;
	ImpRectangle * rect;
	ImpVertex *v1, *v2, *v3, *v4;
	ImpEdge *es, *e1, *e2, *e3, *e4, *e5;

	ImpVertex *_v1, *_v2, *_v3, *_v4;
	ImpEdge *_e1, *_e2, *_e3, *_e4;

	ListIterator * it;

	quads = imp_surface_new();

	it = surf->faces->first;
	while (it) {
		T = IMP_TRIANGLE(it->data);
		it = it->next;

		T1 = imp_triangle_get_opposite_triangle(T, T->e[0]);
		T2 = imp_triangle_get_opposite_triangle(T, T->e[1]);
		T3 = imp_triangle_get_opposite_triangle(T, T->e[2]);

		ImpTriangle * ts[3];
		ImpEdge * edges[3];

		ts[0] = T1;
		ts[1] = T2;
		ts[2] = T3;

		edges[0] = T->e[0];
		edges[1] = T->e[1];
		edges[2] = T->e[2];

		int i;
		for (i = 0; i < 3; i++) {

			T1 = ts[i];
			es = edges[i];

			if (!T1) continue;
			if (!__is_rect(T, T1, img)) continue;

			imp_triangle_extract(T, es, &v1, &v2, &v3, &e1, &e2, &e3);
			imp_triangle_extract(T1, es, &v1, &v2, &v4, &e1, &e4, &e5);

			_v1 = imp_vertex_new_from_point(v1->parent);
			_v2 = imp_vertex_new_from_point(v3->parent);
			_v3 = imp_vertex_new_from_point(v2->parent);
			_v4 = imp_vertex_new_from_point(v4->parent);

			imp_surface_add_vertex(quads, _v1);
			imp_surface_add_vertex(quads, _v2);
			imp_surface_add_vertex(quads, _v3);
			imp_surface_add_vertex(quads, _v4);

			_e1 = imp_edge_new(_v1, _v2);
			_e2 = imp_edge_new(_v2, _v3);
			_e3 = imp_edge_new(_v3, _v4);
			_e4 = imp_edge_new(_v4, _v1);

			imp_surface_add_edge(quads, _e1);
			imp_surface_add_edge(quads, _e2);
			imp_surface_add_edge(quads, _e3);
			imp_surface_add_edge(quads, _e4);

			rect = imp_rectangle_new(_e1, _e2, _e3, _e4);

			imp_surface_add_rectangle(quads, rect);

			imp_surface_remove_triangle(surf, T);

			break;
		}

	}

	return quads;
}
void imp_rectangle_print(ImpRectangle * p) {

}
*/

